<?php
/**
 * DirectorySystemManager
 *
 * @category	FileSystem
 * @package		dayscript.filesystem
 * @subpackage
 * @author		Noel Marin <nmarin@dayscript.com>
 * @copyright	2009 Dayscript Ltda.
 * @license
 * @version		1.0
 * @version		$Revision: 0 $
 * @filesource
 * @link		http://www.dayscript.com
 * @link		{docsLink}
 * @uses
 * @since		1.0
 * @modifiedby	$LastChangedBy: Noel Marin $
 * @modified	$Date: 2009-08-28 $
 */
namespace dayscript\filesystem;

/**
 * DirectorySystemManager
 *
 * Manage all DirectorySystem object actions
 *
 * @category	FileSystem
 * @package		dayscript.filesystem
 * @subpackage
 * @author		Noel Marin <nmarin@dayscript.com>
 * @copyright	2009 Dayscript Ltda.
 * @license
 * @version		1.0
 * @link		http://www.dayscript.com
 * @link		{docsLink}
 * @uses		\dayscript\exception\ErrorCallerException
 * @since		1.0
 * @modifiedby	$LastChangedBy: Noel Marin $
 * @modified	$Date: 2009-08-28 $
 */
class DirectorySystemManager{

	/**
	 * Creates a new directory if doesn't exists
	 *
	 * @return boolean
	 */
	public static function create(\dayscript\filesystem\DirectorySystem $directorySystem){
		if($directorySystem->exists()){
			throw new \dayscript\exception\ErrorCallerException( "Directory does not exists ", E_USER_ERROR );
		}

		return \mkdir($directorySystem->getName(), $directorySystem->getMode());
	}

	/**
	 * Opens a DirectorySystem
	 *
	 * @param $directorySystem
	 * @return boolean
	 */
	public static function open(\dayscript\filesystem\DirectorySystem $directorySystem){
		if(!isset($directorySystem)){
			throw new \dayscript\exception\ErrorCallerException( "Directory is null ", E_USER_ERROR );
		}

		if(!$directorySystem->exists()){
			throw new \dayscript\exception\ErrorCallerException( "Directory does not exists ", E_USER_WARNING );
		}

		$handle = @\opendir($directorySystem->getName());

		if($handle === false){
			throw new \dayscript\exception\ErrorException( "Directory cannot be opened, see directory permissions ", E_USER_WARNING, 0, __FILE__, __LINE__ );
		}

		$directorySystem->setHandle($handle);
	}

	/**
	 * Returns the filename of the next file from the DirectorySystem. The filenames are returned in the order in which they are stored by the filesystem.
	 *
	 * @param $handle
	 * @return string
	 */
	public static function read($handle){
		if(!isset($handle)){
			throw new \dayscript\exception\ErrorCallerException( "Pointer not valid  ", E_USER_ERROR );
		}

		return \readdir($handle);
	}

	/**
	 * List files and directories inside the specified path
	 *
	 * @param $directorySystem
	 * @return array
	 */
	public static function readComplete(\dayscript\filesystem\DirectorySystem $directorySystem){
		return \scandir($directorySystem->getName(), $directorySystem->getFilesOrder());
	}

	/**
	 * Closes a DirectorySystem
	 *
	 * @param $directorySystem
	 * @return DirectorySystem
	 */
	public static function close(\dayscript\filesystem\DirectorySystem $directorySystem){
		$handle = $directorySystem->getHandle();
		if(!isset($handle)){
			throw new \dayscript\exception\ErrorCallerException( "Open the directory first ", E_USER_ERROR );
		}

		\closedir($handle);
		$directorySystem->setHandle(null);
	}

	/**
	 * Deletes a DirectorySystem
	 *
	 * @param $fileSystem
	 * @return boolean
	 */
	public static function delete(\dayscript\filesystem\DirectorySystem $directorySystem){
		if(!$directorySystem->isEmpty()){
			throw new \dayscript\exception\ErrorCallerException( "Cannot delete none empty directory ", E_USER_ERROR );
		}

		return \rmdir($directorySystem->getName());
	}

	/**
	 * Recursively delete a directory
	 *
	 * @param $fileSystem 
	 * @param $expression Regular expression to delete the match content, if It's not given the method will delete all the directory content
	 * @param $deleteRootToo Delete specified top-level directory as well
	 * @return void
	 */
	public static function deleteContent(\dayscript\filesystem\FileSystem $fileSystem, $expression = null, $deleteRootToo = false){
		$handle = $fileSystem->getHandle();
		if(isset($handle)){
			self::close($fileSystem);
		}

		self::open($fileSystem);
		$handle = $fileSystem->getHandle();

		while(false !== ($file = self::read($handle))){
			if($file == '.' || $file == '..'){
				continue;
			}

			if(isset($expression) and $expression === "" and !\preg_match($expression, $file)){
				continue;
			}

			$tmp = new \dayscript\filesystem\DirectorySystem($fileSystem->getName() . "/" . $file);
			if($tmp->isDirectory()){
				self::deleteContent($tmp, $expression, true);
			}else{
				\dayscript\filesystem\FileSystemManager::delete($tmp);
			}
		}

		self::close($fileSystem);

		if($deleteRootToo){
			self::delete($fileSystem);
		}
	}

	/**
	 * Recursively change the FileSystem's permissions
	 *
	 * @param $directorySystem
	 * @param $permissions Parameter must be an octal number so you need to prefix the parameter with a zero (0)
	 * @return boolean
	 */
	public static function setRecursivePermissions(\dayscript\filesystem\FileSystem $fileSystem, $permissions) {
		if (!$fileSystem->isDirectory()){
			throw new \dayscript\exception\ErrorCallerException( "Parameter is not directory, to delete files use FileSystemManager::setPermissions ", E_USER_ERROR );
		}

		$handle = $fileSystem->getHandle();
		if(isset($handle)){
			self::close($fileSystem);
		}

		self::open($fileSystem);
		$handle = $fileSystem->getHandle();

		while(false !== ($file = self::read($handle))){
			if($file == '.' || $file == '..'){
				continue;
			}

			$tmp = new \dayscript\filesystem\DirectorySystem($fileSystem->getName() . "/" . $file);
			if($tmp->isDirectory()){
				self::setRecursivePermissions($tmp, $permissions);
			}else{
				$tmp->setPermissions($permissions);
			}
		}

		self::close($fileSystem);

		return $fileSystem->setPermissions($permissions);
	}
}